﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Specialized;
using System.IO;
using System.Security.AccessControl;

namespace FileSystemAudit
{
    /// <summary>
    /// utilisez Barrier par la suite
    /// </summary>
    public class AnalyzerManager
    {
        static void Main(string[] args)
        {
            #region Settings
            try
            {
                FileSystemDatabaseEntities dataCtx = new FileSystemDatabaseEntities();
                dataCtx.CreateDatabase();
            }
            catch { }
            try
            {
                Console.SetBufferSize(2048, 2048);
            }
            catch { }
            try
            {
                Console.SetBufferSize(2048 * 2, 2048 * 2);
            }
            catch { }
            try
            {
                Console.SetWindowSize(1024, 1024);
            }
            catch { }
            #endregion

            string folder = "f:\\";

            var factory = new AnalyzerManager();

            #region Color
            var beforeForegroundColor = Console.ForegroundColor;
            var beforeBackgroundColor = Console.BackgroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.BackgroundColor = ConsoleColor.Black;
            #endregion

            Console.WriteLine(" folder " + folder + " will be scanned");

            factory.Processing(folder);

            Console.WriteLine(" folder " + folder + " was scanned");
            Console.WriteLine(" Enter to leave...");

            #region color
            Console.ForegroundColor = beforeForegroundColor;
            Console.BackgroundColor = beforeBackgroundColor;
            #endregion

            Console.ReadLine();
            Console.WriteLine(" Any key to leave...");

            Console.ReadKey();
        }

        public void Begin()
        {
            FileSystemDatabaseEntities dataCtx = null;
            IQueryable<FolderInfos> configRootFolders = null;
            List<FolderInfos> configRootFolderList = new List<FolderInfos>();
            try
            {
                dataCtx = new FileSystemDatabaseEntities();
                configRootFolders = from f in dataCtx.FolderInfos where f.IsRoot.HasValue && f.IsRoot.Value select f;
                if (configRootFolders.Count() == 0)
                {
                    configRootFolders = from f in dataCtx.FolderInfos
                                        where f.Depth == 0
                                        select f;
                    configRootFolders = configRootFolders.Distinct(new FolderInfosComparerOnPath());
                }

                configRootFolderList = configRootFolders.ToList();
                Console.WriteLine("Nb configRootFolders " + configRootFolders.Count());

            }
            catch (Exception exc)
            {
                Console.WriteLine(" " + exc.Message);
            }
            finally
            {
                dataCtx.Dispose();
            }

            try
            {
                Parallel.ForEach(configRootFolderList, rootFolder => Processing(rootFolder.Path));
            }
            catch (Exception exc)
            {
                Console.WriteLine(" " + exc.Message);
            }
        }

        public void Processing(string folder)
        {
            DirectoryInfo di = new DirectoryInfo(folder);
            Processing(di);
        }


        public void Processing(DirectoryInfo directory)
        {
            if (!directory.Exists)
            {
                return;
            }
            #region color
            var beforeForegroundColor = Console.ForegroundColor;
            var beforeBackgroundColor = Console.BackgroundColor;
            Console.ForegroundColor = ConsoleColor.White;
            Console.BackgroundColor = ConsoleColor.Blue;
            #endregion
            Console.WriteLine("Current Folder " + directory.FullName + " on Managed Thread Id " + System.Threading.Thread.CurrentThread.ManagedThreadId);
            #region color
            Console.ForegroundColor = beforeForegroundColor;
            Console.BackgroundColor = beforeBackgroundColor;
            #endregion
            IEnumerable<DirectoryInfo> subFolderQuery = null;
            IEnumerable<FileInfo> fileQuery = null;
            FolderInfos folder = null;
            try
            {
                subFolderQuery = from d in directory.GetDirectories()
                                 where !d.FullName.Contains("$RECYCLE.BIN")
                                 where !d.FullName.Contains("System Volume Information")
                                 select d;

                fileQuery = from file in directory.GetFiles()
                            where IsAccessible(file)
                            select file;

                folder = new FolderInfos()
                {
                    Path = directory.FullName,
                    Uid = Guid.NewGuid(),
                    Name = directory.Name,
                    CreatedDate = directory.CreationTime,
                    LastAcessDate = directory.LastAccessTime,
                    ModifiedDate = directory.LastWriteTime
                };
                folder.Depth = directory.FullName.Count(x => x == '\\');
                folder.NumberOfFiles = directory.GetFiles().Length;
                folder.NumberOfFolder = subFolderQuery.Count();

                SaveFolder(folder);
            }
            catch (AggregateException aggExc)
            {
                Console.WriteLine(aggExc.Message + " " + aggExc.StackTrace);
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message + " " + exc.StackTrace);
            }

            if (folder != null)
                ProcessingFiles(directory, folder);

            if (subFolderQuery != null)
                Parallel.ForEach(subFolderQuery, currentFs => Processing(currentFs));

        }
        private bool IsAccessible(FileInfo fi)
        {
            var res = true;
            AccessControlSections includeSections = AccessControlSections.Access;
            try
            {
                var fileSecurity = fi.GetAccessControl(includeSections);
                //fileSecurity.GetAccessRules(true,true,);
            }
            catch (Exception)
            {
            }
            return res;
        }

        public void SaveFolder(FolderInfos folderInfos)
        {
            using (FileSystemDatabaseEntities entities = new FileSystemDatabaseEntities())
            {
                try
                {
                    entities.FolderInfos.AddObject(folderInfos);
                    entities.SaveChanges();
                }
                catch (System.Data.SqlClient.SqlException sqlExc)
                {
                    Console.WriteLine(sqlExc.Message + " " + sqlExc.StackTrace);
                }
                catch (Exception exc)
                {
                    Console.WriteLine(exc.Message + " " + exc.StackTrace);
                }

            }
        }
        #region ProcessingFiles

        public void ProcessingFiles(DirectoryInfo directory, FolderInfos folderInfos)
        {
            System.IO.FileInfo[] fis = directory.GetFiles();
            ProcessingFiles(fis, folderInfos);
        }
        public void ProcessingFiles(System.IO.FileInfo[] fis, FolderInfos folderInfos)
        {
            Parallel.ForEach(fis, fi => ProcessingFile(fi, folderInfos.Uid));
        }

        public void ProcessingFile(System.IO.FileInfo fi, Guid folderInfosUid)
        {
            #region color
            var beforeForegroundColor = Console.ForegroundColor;
            var beforeBackgroundColor = Console.BackgroundColor;
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.BackgroundColor = ConsoleColor.Red;
            #endregion

            Console.WriteLine("Current file " + fi.FullName + " on Managed Thread Id " + System.Threading.Thread.CurrentThread.ManagedThreadId);
            #region color
            Console.ForegroundColor = beforeForegroundColor;
            Console.BackgroundColor = beforeBackgroundColor;
            #endregion

            var fileinfo = new FileInfos()
            {
                Uid = Guid.NewGuid(),
                Folder = folderInfosUid,
                Path = fi.FullName,
                Name = fi.Name,
                Extension = fi.Extension,
                CreatedDate = fi.CreationTime,
                ModifiedDate = fi.LastWriteTime,
                SizeInKo = fi.Length / 1024,
                SizeInOctets = fi.Length,
                SizeInMo = fi.Length / 1024 / 1024,
                Comment = "file.IsReadOnly:" + fi.IsReadOnly + ";"
            };
            SaveFile(fileinfo);
        }


        public void SaveFile(FileInfos fileInfos)
        {
            using (FileSystemDatabaseEntities entities = new FileSystemDatabaseEntities())
            {
                try
                {
                    entities.FileInfos.AddObject(fileInfos);
                    entities.SaveChanges();
                }
                catch (System.Data.SqlClient.SqlException sqlExc)
                {
                    if (fileInfos.Extension == ".url")
                        Console.WriteLine(sqlExc.Message + " " + sqlExc.StackTrace);
                }
                catch (Exception exc)
                {
                    if (fileInfos.Extension == ".url")
                        Console.WriteLine(exc.Message + " " + exc.StackTrace);

                }
            }
        }
        #endregion
    }
}
